package com.pshcp.patient.tool;

import cn.hutool.core.date.DateUtil;
import com.external.pay.domain.PayReqDTO;
import com.external.ws.soap.entity.dto.CancelRegisterDTO;
import com.external.ws.soap.entity.dto.CancelRegisterPayDTO;
import com.external.ws.soap.entity.dto.OrderRegisterDTO;
import com.external.ws.soap.entity.dto.PayRegConfirmDTO;
import com.external.ws.soap.entity.res.CancelRegisterPayRes;
import com.external.ws.soap.entity.res.CancelRegisterRes;
import com.external.ws.soap.entity.res.OrderRegisterRes;
import com.external.ws.soap.entity.res.PayRegConfirmRes;
import com.framework.base.ResultBuilder;
import com.framework.base.ResultDTO;
import com.framework.thread.ReqComHold;
import com.framework.tool.CommonTool;
import com.pshcp.common.enums.CommonStatusEnum;
import com.pshcp.common.enums.DayTypeEnum;
import com.pshcp.common.enums.MessageTemplateEnum;
import com.pshcp.common.enums.MessageTypeEnum;
import com.pshcp.common.enums.PatCardTypeEnum;
import com.pshcp.common.enums.PayBusinessEnum;
import com.pshcp.common.enums.ReCallHisEnum;
import com.pshcp.common.enums.RegPayStatusEnum;
import com.pshcp.common.enums.RegStatusEnum;
import com.pshcp.common.enums.SchModeEnum;
import com.pshcp.common.enums.UnPayNotifyEnum;
import com.pshcp.common.enums.UserTypeEnum;
import com.pshcp.domain.dto.OrderRegDTO;
import com.pshcp.domain.model.Doctor;
import com.pshcp.domain.model.DoctorSchedule;
import com.pshcp.domain.model.OrderReg;
import com.pshcp.domain.model.Patient;
import com.pshcp.manager.messagenotification.MessageNotificationContentDTO;
import com.pshcp.manager.messagenotification.MessageNotificationDTO;
import com.pshcp.patient.domain.orderreg.ao.RegListAO;
import com.pshcp.patient.domain.orderreg.ao.ToPayAO;
import org.springframework.util.ObjectUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class OrderRegTools {

    public static OrderRegisterDTO buildWsDTO(DoctorSchedule doctorSchedule, String hisPatientId, Integer regType, Patient patient){
        OrderRegisterDTO orderRegisterDTO = new OrderRegisterDTO();
        orderRegisterDTO.setAccessPatId(hisPatientId);
        orderRegisterDTO.setAccessSchId(doctorSchedule.getAccessSchId());
        orderRegisterDTO.setSchId(Long.valueOf(orderRegisterDTO.getAccessSchId()));
        orderRegisterDTO.setRegFee(doctorSchedule.getRegFee());
        orderRegisterDTO.setSchMode(SchModeEnum.USER.getCode()+"");
        orderRegisterDTO.setRegType(regType);
        // 参数处理
        orderRegisterDTO.setRegId(doctorSchedule.getId());
        orderRegisterDTO.setDayType(Integer.parseInt(doctorSchedule.getDayType()));
        orderRegisterDTO.setSchDate(doctorSchedule.getSchDate());
        orderRegisterDTO.setExpectStime(doctorSchedule.getStartTime());
        orderRegisterDTO.setExpectEtime(doctorSchedule.getEndTime());
        orderRegisterDTO.setHosDistId("1");
        orderRegisterDTO.setPatName(patient.getName());
        orderRegisterDTO.setPatCardType(patient.getPatientCardType());
        orderRegisterDTO.setPatCardNO(patient.getPatientCardNo());
        orderRegisterDTO.setBirthDay(DateUtil.format(patient.getBirthday(), "yyyy-MM-dd"));
        orderRegisterDTO.setSex(patient.getSex());
        orderRegisterDTO.setPsvFlag("0");
        orderRegisterDTO.setSignalId("0");
        orderRegisterDTO.setTakenIndex("0");
        orderRegisterDTO.setServiceFee(doctorSchedule.getServiceFee());
        orderRegisterDTO.setIdCardNo(patient.getIdCardNo());
        return orderRegisterDTO;
    }

    public static OrderReg buildWsDTO2Model(OrderRegisterRes registerRes){
        OrderReg orderReg = CommonTool.copyProperties(registerRes, OrderReg.class);
        orderReg.setHisRegId(registerRes.getAccessRegId());
        orderReg.setRegStatus(RegStatusEnum.REG.getCode());
        orderReg.setPayStatus(RegPayStatusEnum.WAIT_PAY.getCode());
        orderReg.setUnPayNotify(UnPayNotifyEnum.NO.getCode());
        return orderReg;
    }

    public static void buildDoctorInfo(OrderReg orderReg, Doctor doctor){
        orderReg.setDoctorId(doctor.getId());
        orderReg.setDoctorName(doctor.getName());
        orderReg.setHisDoctorId(doctor.getHisDoctorId());
        orderReg.setAddress(doctor.getAddress());
    }

    public static void buildPatientInfo(OrderReg orderReg, Patient patient){
        orderReg.setHisPatientId(patient.getHisPatientId());
        orderReg.setPatientUserId(patient.getPatientUserId());
        orderReg.setPatientId(patient.getId());
        orderReg.setPatientName(patient.getName());
        orderReg.setCardNo(patient.getIdCardNo());
        orderReg.setPatCardNo(patient.getPatientCardNo());
        orderReg.setPatPhone(patient.getPhone());
    }

    public static void buildDoctorSchedule(OrderReg orderReg, DoctorSchedule doctorSchedule){
        orderReg.setSchDate(doctorSchedule.getSchDate());
        orderReg.setDayType(Integer.parseInt(doctorSchedule.getDayType()));
        orderReg.setDeptName(doctorSchedule.getDeptName());
        orderReg.setCost(doctorSchedule.getCost());
        orderReg.setRegFee(doctorSchedule.getRegFee());
        orderReg.setServiceFee(doctorSchedule.getServiceFee());
    }

    public static OrderRegDTO buildRegListAO2DTO(RegListAO regListAO){
        OrderRegDTO orderReg = new OrderRegDTO();
        orderReg.setPatientUserId(ReqComHold.getReqCom().getUserId());
        orderReg.setStatus(CommonStatusEnum.INIT.getCode());
        orderReg.setPageNum(regListAO.getPageNum());
        orderReg.setPageSize(regListAO.getPageSize());
        if(regListAO.getLastDay() != null){
            orderReg.setEndTime(new Date());
            orderReg.setStartTime(DateUtil.offsetDay(orderReg.getEndTime(), -regListAO.getLastDay()));
        }
        return orderReg;

    }

    public static PayRegConfirmDTO buildPayRegConfirmDTO(OrderReg orderReg){
        PayRegConfirmDTO confirmDTO = new PayRegConfirmDTO();
        //业务类型: 1-预约挂号 2-商品 3-诊间支付 4-充值
        confirmDTO.setBizType(1);
        confirmDTO.setBizId(orderReg.getId()+"");
        confirmDTO.setAccessBizId(orderReg.getHisRegId());
        confirmDTO.setAmount(orderReg.getCost());
        confirmDTO.setIdCardNo(orderReg.getCardNo());
        confirmDTO.setPatCardType(PatCardTypeEnum.PAT_VISIT_CARD.getCode());
        //patCardNo和setAccessPatId要一样
        confirmDTO.setPatCardNo(orderReg.getHisPatientId());
        confirmDTO.setAccessPatId(orderReg.getHisPatientId());
        confirmDTO.setTradeTime(DateUtil.formatDateTime(orderReg.getCreatedTime()));
        confirmDTO.setExpectStime(orderReg.getExpectStime().substring(11,19));
        confirmDTO.setExpectEtime(orderReg.getExpectEtime().substring(11,19));
        confirmDTO.setYuntaiTradeNo(orderReg.getId()+"");
        confirmDTO.setThirdTradeNo(orderReg.getId()+"");
        confirmDTO.setPayBy(1);
        confirmDTO.setPatName(orderReg.getPatientName());
//        confirmDTO.setAccessSchId("");
//        confirmDTO.setHosDistId("");
//        confirmDTO.setPhoneNo("");
        return confirmDTO;
    }

    public static PayReqDTO buildPayDTO(OrderReg orderReg, ToPayAO toPayAO){
        PayReqDTO payReqDTO = new PayReqDTO();
        payReqDTO.setPayMode(toPayAO.getPayMode());
        payReqDTO.setWechatType(toPayAO.getWechatType());
        payReqDTO.setOpenid(toPayAO.getOpenid());
        payReqDTO.setOrderId(orderReg.getId());
        payReqDTO.setPayBusiness(PayBusinessEnum.REG_PAY.getCode());
        payReqDTO.setAmount(orderReg.getCost());
        payReqDTO.setPatientUserId(orderReg.getPatientUserId());
        return payReqDTO;
    }

    public static void buildPayConfirmRes(OrderReg orderReg, PayRegConfirmRes confirmRes){
        orderReg.setHisPayNo(confirmRes.getAccessPayNo());
        if(!ObjectUtils.isEmpty(confirmRes.getWaitAddr())){
            orderReg.setWaitAddr(confirmRes.getWaitAddr());
        }
        if(!ObjectUtils.isEmpty(confirmRes.getWaitTime())){
            orderReg.setWaitTime(confirmRes.getWaitTime());
        }
        if(!ObjectUtils.isEmpty(confirmRes.getTakenIndex())){
            orderReg.setTakenIndex(confirmRes.getTakenIndex());
        }
        if(!ObjectUtils.isEmpty(confirmRes.getExpectTime())){
            orderReg.setExpectTime(confirmRes.getExpectTime());
        }
        orderReg.setPayStatus(RegPayStatusEnum.PAY_OK.getCode());
        orderReg.setRegStatus(RegStatusEnum.PAY_SUCCESS.getCode());
    }

    public static CancelRegisterDTO buildWsCancelRegisterDTO(OrderReg orderReg){
        CancelRegisterDTO registerDTO = new CancelRegisterDTO();
        registerDTO.setAccessRegId(orderReg.getHisRegId());
        registerDTO.setRefundAmount(orderReg.getRegFee());
        //可空
        registerDTO.setHsOrderId("");
        registerDTO.setAcsPayNo("");
        return registerDTO;
    }

    public static ResultDTO checkWsCancel(CancelRegisterRes res){
        /**
         *  ResultCode 需要特殊处理
         *  * 0取消成功
         *  * 1已取消
         *  * 2已取消且已退费
         *  * 3违约禁止取消
         *  * 4已就诊
         *  * 9其它原因
         *  * 注意：如果HIS能返回错误编码，对接一定要返回， 1 和2两种状态，服务端会更新预约记录。错误信息一并返回
         */
        boolean flag = (res.getResultCode() == 0 || res.getResultCode() == 1 || res.getResultCode() == 2);
        if(flag){
            return ResultBuilder.success();
        }
        return ResultBuilder.failure(res.getResultCode()+"", res.getErrorMsg());
    }

    /**
     * 已支付退号
     * @param orderReg
     * @return
     */
    public static CancelRegisterPayDTO buildCancelRegisterPayDTO(OrderReg orderReg){
        CancelRegisterPayDTO dto = new CancelRegisterPayDTO();
        // HsOrderId = PayRegConfirmDTO.ThirdTradeNo
        dto.setAccessRegId(orderReg.getHisRegId());
        dto.setHsOrderId(orderReg.getId()+"");
        dto.setAcsPayNo(orderReg.getHisPayNo());
        dto.setCancelReason(orderReg.getCancelReason());
        dto.setRefundAmount(orderReg.getCost());
        return dto;
    }

    public static ResultDTO checkWsRefund(CancelRegisterPayRes res){
        /**
         *
         * resultCode 含义
         * 0取消成功
         * 1已取消
         * 2已取消且已退费
         * 3违约禁止取消
         * 4已就诊
         * 9其它原因
         * 注意：如果HIS能返回错误编码，对接一定要返回， 1 和2两种状态，服务端会更新预约记录。错误信息一并返回
         */
        boolean flag = (res.getResultCode() == 0 || res.getResultCode() == 1 || res.getResultCode() == 2);
        if(flag){
            return ResultBuilder.success();
        }
        return ResultBuilder.failure(res.getResultCode()+"", res.getErrorMsg());
    }

    public static void buildCancelRegInfo(OrderReg orderReg, CancelRegisterRes res){
        orderReg.setReCallHis(ReCallHisEnum.OK.getCode());
        orderReg.setRegStatus(RegStatusEnum.CANCEL_REG.getCode());
        //修改状态支付失败
        orderReg.setPayStatus(RegPayStatusEnum.PAY_FAIL.getCode());
        // 取消原因   取消时间
        if(!ObjectUtils.isEmpty(res.getCancleTime())){
            orderReg.setCancelTime(DateUtil.parseDateTime(res.getCancleTime()));
        }
        if(!ObjectUtils.isEmpty(res.getCancleReason())){
            orderReg.setCancelReason(res.getCancleReason());
        }
    }

    public static void buildRefundRegInfo(OrderReg orderReg, CancelRegisterPayRes res){
        orderReg.setReCallHis(ReCallHisEnum.OK.getCode());
        orderReg.setRegStatus(RegStatusEnum.QUIT.getCode());
        //修改状态 退款中，定时任务退款
        orderReg.setPayStatus(RegPayStatusEnum.LAUNCH_REFUND.getCode());
        if(BigDecimal.ZERO.compareTo(orderReg.getCost()) >= 0){
            orderReg.setPayStatus(RegPayStatusEnum.REFUND_OK.getCode());
        }
        // 取消原因   取消时间
        if(!ObjectUtils.isEmpty(res.getCancleTime())){
            orderReg.setCancelTime(DateUtil.parseDateTime(res.getCancleTime()));
        }
        if(!ObjectUtils.isEmpty(res.getCancleReason())){
            orderReg.setCancelReason(res.getCancleReason());
        }
    }

    /**
     * 调用his接口取消失败
     * @param orderReg
     */
    public static void buildWsRefundFail(OrderReg orderReg){
        orderReg.setReCallHis(ReCallHisEnum.REFUND_FAIL.getCode());
    }

    /**
     * 挂号单
     * @param orderReg
     * @return
     */
    public static MessageNotificationDTO buildRegOrderMessage(OrderReg orderReg){
        MessageNotificationDTO dto = new MessageNotificationDTO();
        dto.setDataId(orderReg.getId());
        dto.setUserType(UserTypeEnum.PATIENT.getCode());
        dto.setMessageType(MessageTypeEnum.REG_ORDER.getCode());
        dto.setUserId(orderReg.getPatientUserId());
        dto.setTitle(MessageTemplateEnum.REG_ORDER_OK.getTitle());
        String desc = String.format(MessageTemplateEnum.REG_ORDER_OK.getDesc(), orderReg.getPatientName(), orderReg.getPatCardNo());
        dto.setDescription(desc);
        dto.setContents(buildContent(orderReg));
        return dto;
    }

    /**
     * 取消挂号单
     * @param orderReg
     * @return
     */
    public static MessageNotificationDTO buildCancelOrderMessage(OrderReg orderReg){
        MessageNotificationDTO dto = new MessageNotificationDTO();
        dto.setDataId(orderReg.getId());
        dto.setUserType(UserTypeEnum.PATIENT.getCode());
        dto.setMessageType(MessageTypeEnum.CANCEL_ORDER.getCode());
        dto.setUserId(orderReg.getPatientUserId());

        dto.setTitle(MessageTemplateEnum.CANCEL_ORDER_OK.getTitle());
        String desc = String.format(MessageTemplateEnum.CANCEL_ORDER_OK.getDesc(), orderReg.getPatientName(), orderReg.getPatCardNo());
        dto.setDescription(desc);
        dto.setContents(buildContent(orderReg));
        return dto;
    }

    /**
     * 挂号单退号
     * @param orderReg
     * @return
     */
    public static MessageNotificationDTO buildRefundOrderMessage(OrderReg orderReg){
        MessageNotificationDTO dto = new MessageNotificationDTO();
        dto.setDataId(orderReg.getId());
        dto.setUserType(UserTypeEnum.PATIENT.getCode());
        dto.setMessageType(MessageTypeEnum.CANCEL_ORDER.getCode());
        dto.setUserId(orderReg.getPatientUserId());

        dto.setTitle(MessageTemplateEnum.REFUND_ORDER_OK.getTitle());
        String desc = String.format(MessageTemplateEnum.REFUND_ORDER_OK.getDesc(), orderReg.getPatientName(), orderReg.getPatCardNo());
        dto.setDescription(desc);
        dto.setContents(buildContent(orderReg));
        return dto;
    }

    /**
     * 挂号单退费通知
     * @param orderReg
     * @return
     */
    public static MessageNotificationDTO buildRefundPayFeeMessage(OrderReg orderReg){
        MessageNotificationDTO dto = new MessageNotificationDTO();
        dto.setDataId(orderReg.getId());
        dto.setUserType(UserTypeEnum.PATIENT.getCode());
        dto.setMessageType(MessageTypeEnum.CANCEL_ORDER.getCode());
        dto.setUserId(orderReg.getPatientUserId());

        MessageTemplateEnum refundPay = MessageTemplateEnum.REFUND_PAY_FEE_OK;
        if(RegPayStatusEnum.REFUND_FAIL.getCode().equals(orderReg.getPayStatus())){
            refundPay = MessageTemplateEnum.REFUND_PAY_FEE_FAIL;
        }
        dto.setTitle(refundPay.getTitle());
        String desc = String.format(refundPay.getDesc(), orderReg.getPatientName(), orderReg.getPatCardNo());
        dto.setDescription(desc);
        dto.setContents(buildContent(orderReg));
        return dto;
    }

    /**
     * 超时未支付
     * @param orderReg
     * @return
     */
    public static MessageNotificationDTO buildTimeoutUnPayOrderMessage(OrderReg orderReg, Integer timeout){
        MessageNotificationDTO dto = new MessageNotificationDTO();
        dto.setDataId(orderReg.getId());
        dto.setUserType(UserTypeEnum.PATIENT.getCode());
        dto.setMessageType(MessageTypeEnum.REG_ORDER.getCode());
        dto.setUserId(orderReg.getPatientUserId());

        MessageTemplateEnum templateEnum = MessageTemplateEnum.UN_PAY;
        dto.setTitle(templateEnum.getTitle());
        String desc = String.format(templateEnum.getDesc(),
                orderReg.getPatientName(), orderReg.getPatCardNo(), timeout);
        dto.setDescription(desc);
        dto.setContents(buildContent(orderReg));
        return dto;
    }

    private static List<MessageNotificationContentDTO> buildContent(OrderReg orderReg){
        List<MessageNotificationContentDTO> contentDTOList = new ArrayList<>();
        MessageNotificationContentDTO hos = new MessageNotificationContentDTO();
        hos.setLabel("医院");
        hos.setValue(orderReg.getHosName());
        contentDTOList.add(hos);

        MessageNotificationContentDTO dept = new MessageNotificationContentDTO();
        dept.setLabel("科室");
        dept.setValue(orderReg.getDeptName());
        contentDTOList.add(dept);

        MessageNotificationContentDTO doc = new MessageNotificationContentDTO();
        doc.setLabel("医生");
        doc.setValue(orderReg.getDoctorName());
        contentDTOList.add(doc);

        MessageNotificationContentDTO times = new MessageNotificationContentDTO();
        times.setLabel("就诊时间");
        times.setValue(orderReg.getSchDate() + " "
                + DayTypeEnum.getDescByCode(orderReg.getDayType()) + " "
                + (ObjectUtils.isEmpty(orderReg.getExpectTime()) ? "":orderReg.getExpectTime()));
        contentDTOList.add(times);
        return contentDTOList;
    }

}
